package com.gf.gateway.filter;

import cn.hutool.json.JSONUtil;
import com.gf.gateway.common.R;
import com.gf.gateway.config.GateWayProperties;
import com.gf.gateway.config.JWTProperties;
import com.gf.gateway.config.SecurityConstants;
import com.gf.gateway.config.TokenProvider;
import com.gf.gateway.util.RedisUtils;
import io.jsonwebtoken.Claims;
import io.netty.util.internal.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Objects;

/**
 * @author gFly
 * @date 2024/1/12 15:24
 * @Describe
 */

@Component
@Slf4j
public class AuthFilter implements GlobalFilter, Ordered {

    private final GateWayProperties gateWayProperties;
    private final TokenProvider tokenProvider;
    private final JWTProperties jwtProperties;

    private final RedisUtils redisUtils;

    public AuthFilter(GateWayProperties gateWayProperties, JWTProperties jwtProperties, TokenProvider tokenProvider, RedisUtils redisUtils) {
        this.gateWayProperties = gateWayProperties;
        this.jwtProperties = jwtProperties;
        this.tokenProvider = tokenProvider;
        this.redisUtils = redisUtils;
    }


    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String path = exchange.getRequest().getURI().getPath();
        if (matches(path, gateWayProperties.getWhiteList())) {
            log.info("跳过该验证：{}", path);
            return chain.filter(exchange);
        }

//        String token = exchange.getRequest().getHeaders().getFirst(SecurityConstants.AUTHORIZATION_HEADER);
//        if (StringUtil.isNullOrEmpty(token)) {
//            return setUnauthorizedResponse(exchange, "token信息不存在");
//        }
//
//        token = token.replace(jwtProperties.getTokenStartWith(), "");
//        String loginKey = tokenProvider.loginKey(token);
//        if (!redisUtils.hasKey(loginKey)) {
//            return setUnauthorizedResponse(exchange, "token信息已过期");
//        }
//
//        Claims claims = tokenProvider.tokenValidate(token);
//        if (Objects.isNull(claims) || StringUtil.isNullOrEmpty(claims.getSubject())) {
//            return setUnauthorizedResponse(exchange, "令牌验证失败");
//        }
//        ServerHttpRequest request = exchange.getRequest();
//        ServerHttpRequest.Builder mutate = request.mutate();
//
//        addHeader(mutate, SecurityConstants.DETAILS_USER_ID, tokenProvider.getValue(claims, SecurityConstants.DETAILS_USER_ID));
//        addHeader(mutate, SecurityConstants.DETAILS_USERNAME, tokenProvider.getValue(claims, SecurityConstants.DETAILS_USERNAME));
        log.info("认证执行完成 url:{}", path);
        return chain.filter(exchange);
    }

    private void addHeader(ServerHttpRequest.Builder mutate, String key, Object value) {
        if (value == null) {
            return;
        }
        String valueEncode = urlEncode(value.toString());
        mutate.header(key, valueEncode);
    }

    public String urlEncode(String str) {
        return URLEncoder.encode(str, StandardCharsets.UTF_8);
    }


    /**
     * 查找指定字符串是否匹配指定字符串列表中的任意一个字符串
     *
     * @param path      指定字符串
     * @param whiteList 需要检查的字符串数组
     * @return 是否匹配
     */
    private boolean matches(String path, List<String> whiteList) {
        if (whiteList.isEmpty() || StringUtil.isNullOrEmpty(path)) {
            return false;
        }
        for (String pattern : whiteList) {
            if (isMatch(pattern, path)) {
                return true;
            }
        }
        return false;
    }

    /**
     * @param pattern 匹配规则
     * @param path    需要匹配url
     */
    private boolean isMatch(String pattern, String path) {
        AntPathMatcher antPathMatcher = new AntPathMatcher();
        return antPathMatcher.match(pattern, path);
    }

    /**
     * 多个过滤器过滤顺序,越小越靠前
     *
     * @return
     */
    @Override
    public int getOrder() {
        return -200;
    }

    private Mono<Void> setUnauthorizedResponse(ServerWebExchange exchange, String msg) {
        ServerHttpResponse response = exchange.getResponse();
        response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
        response.setStatusCode(HttpStatus.OK);

        log.error("[鉴权异常处理]请求路径:{} msg:{}", exchange.getRequest().getPath(), msg);
        return response.writeWith(Mono.fromSupplier(() -> {
            DataBufferFactory dataBufferFactory = response.bufferFactory();
            return dataBufferFactory.wrap(JSONUtil.toJsonStr(R.failed(String.valueOf(HttpStatus.UNAUTHORIZED.value()), msg)).getBytes());
        }));
    }
}
